﻿using Microsoft.Extensions.Logging;
using SqlSugar;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace Ongoal.Quotation.Sqlsugar
{

    public class DbFactory : IDbFactory
    {
        private readonly ILogger _logger;

        private Dictionary<string, ConnectionConfig> _config;

        private static volatile ConcurrentDictionary<string, SqlSugarScope> SqlSugarScopeList = new ConcurrentDictionary<string, SqlSugarScope>();

        private static object SqlSugarScopeLock = new object();

        public DbFactory(List<DbConfig> config, ILogger<DbFactory> logger)
        {
            _logger = logger;
            _config = new Dictionary<string, ConnectionConfig>();
            foreach (DbConfig item in config)
            {
                if (!_config.ContainsKey(item.Name))
                {
                    _config.Add(item.Name, GetConfig(item));
                }
            }
        }

        private ConnectionConfig GetConfig(DbConfig cfg)
        {
            string connectionString = "";
            List<string> list = new List<string>();
            list.Add(cfg.ConnectionStr);
            if (cfg.Slave != null && cfg.Slave.Count > 0)
            {
                list.AddRange(cfg.Slave);
            }

            List<SlaveConnectionConfig> list2 = new List<SlaveConnectionConfig>();
            for (int i = 0; i < list.Count; i++)
            {
                if (i == 0)
                {
                    connectionString = list[i];
                    continue;
                }

                list2.Add(new SlaveConnectionConfig
                {
                    HitRate = i * 2,
                    ConnectionString = list[i]
                });
            }

            return new ConnectionConfig
            {
                ConnectionString = connectionString,
                DbType = (DbType)Enum.Parse(typeof(DbType), cfg.DbType),
                IsAutoCloseConnection = true,
                SlaveConnectionConfigs = list2,
                InitKeyType = InitKeyType.Attribute
            };
        }

        public SqlSugarClient GetDbContext(string name = "", bool IsFilterRule = true)
        {
            return GetDbContext((Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>>)null, name, IsFilterRule);
        }

        public SqlSugarClient GetDbContext(Action<Exception> onErrorEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbContext(null, null, onErrorEvent, name, IsFilterRule);
        }

        public SqlSugarClient GetDbContext(Action<string, SugarParameter[]> onExecutedEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbContext(onExecutedEvent, name, IsFilterRule);
        }

        public SqlSugarClient GetDbContext(Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbContext(null, onExecutingChangeSqlEvent, null, name, IsFilterRule);
        }

        public SqlSugarClient GetDbContext(Action<string, SugarParameter[]> onExecutedEvent = null, Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent = null, Action<Exception> onErrorEvent = null, string name = "", bool IsFilterRule = true)
        {
            return GetDbContext(null, onExecutedEvent, onExecutingChangeSqlEvent, onErrorEvent, null, name, IsFilterRule);
        }

        public SqlSugarClient GetDbContext(Action<string, SugarParameter[]> OnLogExecuting = null, Action<string, SugarParameter[]> onExecutedEvent = null, Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent = null, Action<Exception> onErrorEvent = null, Action<DiffLogModel> OnDiffLogEvent = null, string name = "", bool IsFilterRule = true)
        {
            Action<string, SugarParameter[]> OnLogExecuting2 = OnLogExecuting;
            Action<Exception> onErrorEvent2 = onErrorEvent;
            if (_config.Count == 0)
            {
                throw new Exception("加载数据库连接配置失败，请检查是否配置了正确的数据库连接");
            }

            if (!string.IsNullOrEmpty(name) && !_config.ContainsKey(name))
            {
                throw new Exception("加载名称为[" + name + "]的数据库连接配置失败");
            }

            ConnectionConfig config = (string.IsNullOrEmpty(name) ? _config.First().Value : _config[name]);
            SqlSugarClient db = null;
            SqlSugarClient sqlSugarClient = new SqlSugarClient(config);
            sqlSugarClient.Aop.OnExecutingChangeSql = onExecutingChangeSqlEvent;
            sqlSugarClient.Aop.OnLogExecuted = delegate (string sqls, SugarParameter[] paras)
            {
                string text2 = "";
                foreach (SugarParameter sugarParameter2 in paras)
                {
                    text2 += $"参数名：{sugarParameter2.ParameterName},参数值:{sugarParameter2.Value}";
                }

                _logger.Log(LogLevel.Information, $"执行SQL:{sqls} 参数：{text2} 执行时间：{db.Ado.SqlExecutionTime.TotalMilliseconds}毫秒");
                _ = Debugger.IsAttached;
                if (OnLogExecuting2 != null)
                {
                    OnLogExecuting2(sqls, paras);
                }
            };
            sqlSugarClient.Aop.OnLogExecuting = OnLogExecuting2;
            sqlSugarClient.Aop.OnError = delegate (SqlSugarException err)
            {
                string text = "执行SQL错误：";
                if (!string.IsNullOrEmpty(err.Sql))
                {
                    text = text + "执行SQL:" + err.Sql + ",";
                }

                if (err.Parametres is SugarParameter[] && err.Parametres != null)
                {
                    SugarParameter[] obj = err.Parametres as SugarParameter[];
                    text += "执行参数:";
                    SugarParameter[] array = obj;
                    foreach (SugarParameter sugarParameter in array)
                    {
                        text += $"参数名：{sugarParameter.ParameterName},参数值:{sugarParameter.Value}";
                    }
                }

                text = text + "错误信息：" + err.Message + ",错误堆栈信息：" + err.StackTrace;
                _logger.Log(LogLevel.Error, text);
                _ = Debugger.IsAttached;
                if (onErrorEvent2 != null)
                {
                    onErrorEvent2(err);
                }
            };
            sqlSugarClient.Aop.OnDiffLogEvent = OnDiffLogEvent;
            db = sqlSugarClient;
            return db;
        }

        public SqlSugarScope GetDbScope(string name = "")
        {
            return GetDbScope(null, name, true);
        }
        public SqlSugarScope GetDbScope(string name = "", bool IsFilterRule = true)
        {
            return GetDbScope(null, name, IsFilterRule);
        }

        public SqlSugarScope GetDbScope(Action<Exception> onErrorEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbScope(null, null, onErrorEvent, name, IsFilterRule);
        }

        public SqlSugarScope GetDbScope(Action<string, SugarParameter[]> onExecutedEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbScope(onExecutedEvent, name, IsFilterRule);
        }

        public SqlSugarScope GetDbScope(Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent, string name = "", bool IsFilterRule = true)
        {
            return GetDbScope(null, onExecutingChangeSqlEvent, null, name, IsFilterRule);
        }

        public SqlSugarScope GetDbScope(Action<string, SugarParameter[]> onExecutedEvent = null, Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent = null, Action<Exception> onErrorEvent = null, string name = "", bool IsFilterRule = true)
        {
            return GetDbScope(null, onExecutedEvent, onExecutingChangeSqlEvent, onErrorEvent, null, name, IsFilterRule);
        }

        public SqlSugarScope GetDbScope(Action<string, SugarParameter[]> OnLogExecuting = null, Action<string, SugarParameter[]> onExecutedEvent = null, Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent = null, Action<Exception> onErrorEvent = null, Action<DiffLogModel> OnDiffLogEvent = null, string name = "", bool IsFilterRule = true)
        {
            if (_config.Count == 0)
            {
                throw new Exception("加载数据库连接配置失败，请检查是否配置了正确的数据库连接");
            }

            if (!string.IsNullOrEmpty(name) && !_config.ContainsKey(name))
            {
                throw new Exception("加载名称为[" + name + "]的数据库连接配置失败");
            }

            if (SqlSugarScopeList.ContainsKey(name))
            {
                return SqlSugarScopeList[name];
            }

            SqlSugarScope sqlSugarScope = null;
            lock (SqlSugarScopeLock)
            {
                if (SqlSugarScopeList.ContainsKey(name))
                {
                    return SqlSugarScopeList[name];
                }

                ConnectionConfig cfg = (string.IsNullOrEmpty(name) ? _config.First().Value : _config[name]);
                sqlSugarScope = GetSqlSugarScope(cfg, OnLogExecuting, onExecutedEvent, onExecutingChangeSqlEvent, onErrorEvent, OnDiffLogEvent, name, IsFilterRule);
                if (sqlSugarScope != null)
                {
                    SqlSugarScopeList.TryAdd(name, sqlSugarScope);
                }
            }

            return sqlSugarScope;
        }

        private SqlSugarScope GetSqlSugarScope(ConnectionConfig cfg, Action<string, SugarParameter[]> OnLogExecuting = null, Action<string, SugarParameter[]> onExecutedEvent = null, Func<string, SugarParameter[], KeyValuePair<string, SugarParameter[]>> onExecutingChangeSqlEvent = null, Action<Exception> onErrorEvent = null, Action<DiffLogModel> OnDiffLogEvent = null, string name = "", bool IsFilterRule = true)
        {
            Action<string, SugarParameter[]> OnLogExecuting2 = OnLogExecuting;
            Action<Exception> onErrorEvent2 = onErrorEvent;
            SqlSugarScope db = null;
            SqlSugarScope sqlSugarScope = new SqlSugarScope(cfg);
            sqlSugarScope.Aop.OnExecutingChangeSql = onExecutingChangeSqlEvent;
            sqlSugarScope.Aop.OnLogExecuted = delegate (string sqls, SugarParameter[] paras)
            {
                string text2 = "";
                foreach (SugarParameter sugarParameter2 in paras)
                {
                    text2 += $"参数名：{sugarParameter2.ParameterName},参数值:{sugarParameter2.Value}";
                }

                _logger.Log(LogLevel.Information, $"执行SQL:{sqls} 参数：{text2} 执行时间：{db.Ado.SqlExecutionTime.TotalMilliseconds}毫秒");
                _ = Debugger.IsAttached;
                if (OnLogExecuting2 != null)
                {
                    OnLogExecuting2(sqls, paras);
                }
            };
            sqlSugarScope.Aop.OnLogExecuting = OnLogExecuting2;
            sqlSugarScope.Aop.OnError = delegate (SqlSugarException err)
            {
                string text = "执行SQL错误：";
                if (!string.IsNullOrEmpty(err.Sql))
                {
                    text = text + "执行SQL:" + err.Sql + ",";
                }

                if (err.Parametres is SugarParameter[] && err.Parametres != null)
                {
                    SugarParameter[] obj = err.Parametres as SugarParameter[];
                    text += "执行参数:";
                    SugarParameter[] array = obj;
                    foreach (SugarParameter sugarParameter in array)
                    {
                        text += $"参数名：{sugarParameter.ParameterName},参数值:{sugarParameter.Value}";
                    }
                }

                text = text + "错误信息：" + err.Message + ",错误堆栈信息：" + err.StackTrace;
                _logger.Log(LogLevel.Error, text);
                _ = Debugger.IsAttached;
                if (onErrorEvent2 != null)
                {
                    onErrorEvent2(err);
                }
            };
            sqlSugarScope.Aop.OnDiffLogEvent = OnDiffLogEvent;
            db = sqlSugarScope;
            return db;
        }
    }

}
